原題:
https://cses.fi/problemset/task/1687
題意:
給定一棵以 1 為根的樹(每點給父親),處理 q 次查詢:問節點 x 的 第 k 個祖先(不存在輸出 -1)。
解題思路:
#include <bits/stdc++.h>
using namespace std;
int main(){
    int n, q;
    cin >> n >> q;
    const int LOG = 20;
    vector<vector<int>> up(LOG, vector<int>(n+1, 0));
    for(int v=2; v<=n; ++v){
        int p; cin >> p;
        up[0][v] = p; // 父親
    }
    // up[j][1..n]
    for(int j=1; j<LOG; ++j){
        for(int v=1; v<=n; ++v){
            int mid = up[j-1][v];
            up[j][v] = (mid ? up[j-1][mid] : 0);
        }
    }
    auto kth = [&](int v, long long k){
        for(int j=0; j<LOG && v; ++j){
            if(k & (1LL<<j)) v = up[j][v];
        }
        return v;
    };
    while(q--){
        int x; long long k;
        cin >> x >> k;
        int ans = kth(x, k);
        cout << (ans? ans : -1) << "\n";
    }
    return 0;
}
原題:
https://cses.fi/problemset/task/1688
題意:
同一棵樹(以 1 為根),處理 q 次查詢:輸出節點 a 與 b 的 LCA。
解題思路:
建圖、以 1 為根 DFS 得 depth[] 與 up[v][j]。
實作 lca(u,v):先拉平深度,再自高位往低位同步跳。
#include <bits/stdc++.h>
using namespace std;
int main(){
    int n, q;
    cin >> n >> q;
    const int LOG = 20;
    vector<vector<int>> g(n+1);
    vector<vector<int>> up(LOG, vector<int>(n+1, 0));
    vector<int> depth(n+1, 0);
    for(int v=2; v<=n; ++v){
        int p; cin >> p;
        g[p].push_back(v);
        g[v].push_back(p);
    }
    // DFS 建 depth 與 up
    {
        int root = 1;
        vector<int> st = {root}, parent(n+1, 0);
        parent[root] = 0; depth[root] = 0;
        while(!st.empty()){
            int u = st.back(); st.pop_back();
            up[0][u] = parent[u];
            for(int v: g[u]){
                if(v == parent[u]) continue;
                parent[v] = u;
                depth[v] = depth[u] + 1;
                st.push_back(v);
            }
        }
        for(int j=1; j<LOG; ++j){
            for(int v=1; v<=n; ++v){
                int mid = up[j-1][v];
                up[j][v] = (mid ? up[j-1][mid] : 0);
            }
        }
    }
    auto lift = [&](int v, int k){
        for(int j=0; j<LOG && v; ++j)
            if(k & (1<<j)) v = up[j][v];
        return v;
    };
    auto lca = [&](int a, int b){
        if(depth[a] < depth[b]) swap(a,b);
        a = lift(a, depth[a]-depth[b]);
        if(a==b) return a;
        for(int j=LOG-1; j>=0; --j){
            if(up[j][a] != up[j][b]){
                a = up[j][a];
                b = up[j][b];
            }
        }
        return up[0][a]; // 其父即 LCA
    };
    while(q--){
        int a,b;
        cin >> a >> b;
        cout << lca(a,b) << "\n";
    }
    return 0;
}
原題:
https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/description/
題意:
給二元樹根 root 與節點 p,q,求兩者之 最近共同祖先。
解題思路:
/**
 * Definition for a binary tree node.
 * struct TreeNode { int val; TreeNode *left; TreeNode *right;
 *   TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *   TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *   TreeNode(int x, TreeNode *l, TreeNode *r) : val(x), left(l), right(r) {}
 * };
 */
class Solution {
    TreeNode* ans = nullptr;
    bool dfs(TreeNode* u, TreeNode* p, TreeNode* q){
        if(!u) return false;
        bool L = dfs(u->left, p, q);
        bool R = dfs(u->right, p, q);
        bool C = (u==p || u==q);
        if((L&&R) || (C&&(L||R))) ans = u;
        return L || R || C;
    }
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        dfs(root, p, q);
        return ans;
    }
};
原題:
https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/
題意:
同 LCA,但樹是 BST。利用 BST 的序性加速。
解題思路
class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        int a = p->val, b = q->val;
        while(root){
            if(a < root->val && b < root->val) root = root->left;
            else if(a > root->val && b > root->val) root = root->right;
            else return root;
        }
        return nullptr;
    }
};